﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Revit;
using YJKRevitBase.WinForm;
using YRevitJig;
using YJKPresentation.Utils;

namespace YJKAreaStatistic.Forms
{
	public class SelectAreaManager
	{
		public bool IfClose
		{
			get
			{
				return this.m_bIfClose;
			}
		}

		public SelectAreaManager(ExternalCommandData commandData, bool bIsCloseBtn)
		{
			this.m_Revit = commandData;
			this.m_useApplication = this.m_Revit.Application;
			this.m_Doc = this.m_useApplication.ActiveUIDocument.Document;
			this.m_sel = commandData.Application.ActiveUIDocument.Selection;
			this.m_bIsExistClose = bIsCloseBtn;
		}

		[DllImport("user32.dll", EntryPoint = "SendMessageA")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

		public Result EditOutLine()
		{
			if (this.m_Doc.ActiveView.SketchPlane == null)
			{
				Transaction transaction = null;
				try
				{
					transaction = new Transaction(this.m_Doc);
					transaction.Start("new work plane");
					Plane plane = RevitVersionFuncs.CreatePlanByNormalAndOrigin(this.m_Doc.ActiveView.ViewDirection, this.m_Doc.ActiveView.Origin);
					SketchPlane sketchPlane = SketchPlane.Create(this.m_Doc, plane);
					this.m_Doc.ActiveView.SketchPlane = sketchPlane;
					transaction.Commit();
				}
				catch (Exception)
				{
					if (transaction != null)
					{
						transaction.RollBack();
					}
					return Autodesk.Revit.UI.Result.Failed;
				}
			}
			this.linePattern = SelectAreaManager.CreateLinePatternElement(this.m_Doc, "绘制面积边界");
			DlgAreaSelToolbar dlgAreaSelToolbar = new DlgAreaSelToolbar(this.m_bIsExistClose);
			dlgAreaSelToolbar.Show(SelectAreaManager._hWndRevit);
			int wMsg = 7;
			SelectAreaManager.SendMessage(SelectAreaManager._hWndRevit.Handle, wMsg, IntPtr.Zero, IntPtr.Zero);
			Transaction transaction2 = new Transaction(this.m_Doc, "str");
			transaction2.Start();
			this.GetLineStyle();
			transaction2.Commit();
			Result result = Autodesk.Revit.UI.Result.Cancelled;
			try
			{
				for (;;)
				{
					switch (dlgAreaSelToolbar.CurrentOperateType)
					{
					case DlgAreaSelToolbar.OperateType.OT_DrawLine:
						result = this.DrawLinearOutLine();
						break;
					case DlgAreaSelToolbar.OperateType.OT_DrawRect:
						result = this.DrawRectOutLine();
						break;
					case DlgAreaSelToolbar.OperateType.OT_DrawArc3Pt:
						result = this.DrawArc3PtOutLine();
						break;
					case DlgAreaSelToolbar.OperateType.OT_DrawArcCenter:
						result = this.DrawArcCenterOutLine();
						break;
					case DlgAreaSelToolbar.OperateType.OT_SelectRef:
						result = this.SelectReferenceOutLine();
						break;
					case DlgAreaSelToolbar.OperateType.OT_BoxSelect:
						result = this.SelectRoomByBox();
						break;
					case DlgAreaSelToolbar.OperateType.OT_MultiSelect:
						result = this.SelectRoomByMulti();
						break;
					case DlgAreaSelToolbar.OperateType.OT_Delete:
						result = this.DeleteOutLine();
						break;
					}
					if (result == Autodesk.Revit.UI.Result.Cancelled)
					{
						if (!dlgAreaSelToolbar.PickButton)
						{
							break;
						}
						dlgAreaSelToolbar.PickButton = false;
					}
				}
			}
			catch (Exception)
			{
				dlgAreaSelToolbar.Close();
				return Autodesk.Revit.UI.Result.Failed;
			}
			dlgAreaSelToolbar.Close();
			this.m_bIfOk = dlgAreaSelToolbar.IfOk;
			this.m_bIfClose = dlgAreaSelToolbar.IfClose;
			this.m_bIfWinFormClose = dlgAreaSelToolbar.IfWinFormClose;
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private Result SelectRoomByBox()
		{
			new ElementSet();
			try
			{
				IList<Element> source = this.m_Revit.Application.ActiveUIDocument.Selection.PickElementsByRectangle(this.filter, "请框选房间生成面积");
				this.m_lstSelectRooms = source.ToList<Element>();
			}
			catch (Exception)
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			return Autodesk.Revit.UI.Result.Failed;
		}

		private Result SelectRoomByMulti()
		{
			try
			{
				foreach (Reference reference in this.m_Revit.Application.ActiveUIDocument.Selection.PickObjects((Autodesk.Revit.UI.Selection.ObjectType)1, this.filter, "请多选房间生成面积"))
				{
					this.m_lstSelectRooms.Add(this.m_Doc.GetElement(reference));
				}
			}
			catch (Exception)
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			return Autodesk.Revit.UI.Result.Failed;
		}

		private Result DrawLinearOutLine()
		{
			try
			{
				if (this.isFirstPoint)
				{
					this.pt1 = this.m_sel.PickPoint("请输入起点");
				}
				XYZ xyz = RevitExtensionAPI.PickOtherPoint(this.pt1, this.m_Revit.Application.ActiveUIDocument, "请输入直线终点");
				Line curve = Line.CreateBound(this.pt1, xyz);
				DetailCurve detailCurve = this.CreateDetailCurve(this.m_Doc, curve, SelectAreaManager.m_LineStyle, this.linePattern);
				this.m_lstDetailCurveId.Add(detailCurve.Id);
				this.pt1 = xyz;
				this.isFirstPoint = false;
			}
			catch (Exception ex)
			{
				ex.ToString();
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private Result DrawRectOutLine()
		{
			try
			{
				this.pt1 = this.m_sel.PickPoint("请输入矩形的起点");
				XYZ pt = RevitExtensionAPI.PickRectOtherPoint(this.pt1, this.m_Revit.Application.ActiveUIDocument, "请输入矩形的对角点");
				foreach (Line curve in SelectAreaManager.CreateRect(this.pt1, pt))
				{
					DetailCurve detailCurve = this.CreateDetailCurve(this.m_Doc, curve, SelectAreaManager.m_LineStyle, this.linePattern);
					this.m_lstDetailCurveId.Add(detailCurve.Id);
				}
				this.isFirstPoint = true;
			}
			catch (Exception ex)
			{
				ex.ToString();
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private Result SelectReferenceOutLine()
		{
			this.m_PickLastPoint = null;
			Transform identity = Transform.Identity;
			identity.Origin = this.m_Doc.ActiveView.Origin;
			identity.BasisX = this.m_Doc.ActiveView.RightDirection;
			identity.BasisY = this.m_Doc.ActiveView.UpDirection;
			identity.BasisZ = this.m_Doc.ActiveView.ViewDirection;
			Transform inverse = identity.Inverse;
			try
			{
				Curve curve = null;
				while (this.PickEdge(ref curve))
				{
					XYZ xyz = curve.GetEndPoint(0);
					xyz = inverse.OfPoint(xyz);
					xyz = identity.OfPoint(new XYZ(xyz.X, xyz.Y, 0.0));
					XYZ xyz2 = curve.GetEndPoint(1);
					xyz2 = inverse.OfPoint(xyz2);
					xyz2 = identity.OfPoint(new XYZ(xyz2.X, xyz2.Y, 0.0));
					if (!Geometry.IsEqual(xyz.DistanceTo(xyz2), 0.0))
					{
						if (curve.GetType() == typeof(Line))
						{
							this.DrawLines(new List<Curve>
							{
								Line.CreateBound(xyz, xyz2)
							}, true);
						}
						else if (curve.GetType() == typeof(Arc))
						{
							Arc arc = curve as Arc;
							XYZ xyz3 = arc.Center;
							xyz3 = inverse.OfPoint(xyz3);
							xyz3 = identity.OfPoint(new XYZ(xyz3.X, xyz3.Y, 0.0));
							if (!Geometry.IsEqual(arc.Normal, this.m_Doc.ActiveView.ViewDirection))
							{
								XYZ xyz4 = xyz;
								xyz = xyz2;
								xyz2 = xyz4;
							}
							double radius = arc.Radius;
							double angle = Geometry.getAngle(xyz3, xyz, this.m_Doc.ActiveView.RightDirection, this.m_Doc.ActiveView.ViewDirection);
							double angle2 = Geometry.getAngle(xyz3, xyz2, this.m_Doc.ActiveView.RightDirection, this.m_Doc.ActiveView.ViewDirection);
							double num = Geometry.BetweenTheAngles(angle, angle2, true);
							XYZ xyz5 = Geometry.RotateTo(xyz - xyz3, num / 2.0, this.m_Doc.ActiveView.ViewDirection);
							XYZ xyz6 = xyz3 + xyz5;
							this.DrawLines(new List<Curve>
							{
								Arc.Create(xyz, xyz2, xyz6)
							}, true);
						}
					}
				}
			}
			catch (Exception ex)
			{
				ex.ToString();
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			return Autodesk.Revit.UI.Result.Cancelled;
		}

		private Result DrawArc3PtOutLine()
		{
			try
			{
				if (this.isFirstPoint)
				{
					this.pt1 = this.m_sel.PickPoint("请输入弧线起点");
				}
				XYZ xyz = RevitExtensionAPI.PickOtherPoint(this.pt1, this.m_Revit.Application.ActiveUIDocument, "请输入弧线终点");
				XYZ xyz2 = RevitExtensionAPI.PickArcMidPoint(this.pt1, xyz, this.m_Revit.Application.ActiveUIDocument, "请输入弧线上一点");
				Arc curve = Arc.Create(this.pt1, xyz, xyz2);
				DetailCurve detailCurve = this.CreateDetailCurve(this.m_Doc, curve, SelectAreaManager.m_LineStyle, this.linePattern);
				this.m_lstDetailCurveId.Add(detailCurve.Id);
				this.pt1 = xyz;
				this.isFirstPoint = false;
			}
			catch (Exception ex)
			{
				ex.ToString();
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private Result DrawArcCenterOutLine()
		{
			try
			{
				this.pt1 = this.m_sel.PickPoint("请输入圆心");
				XYZ xyz = this.m_sel.PickPoint("请输入弧线起点");
				XYZ ptArcEnd = RevitExtensionAPI.PickArcEndPoint(xyz, this.pt1, this.m_Revit.Application.ActiveUIDocument, "请输入弧线终点");
				Arc curve = SelectAreaManager.CreateArc(this.pt1, xyz, ptArcEnd);
				DetailCurve detailCurve = this.CreateDetailCurve(this.m_Doc, curve, SelectAreaManager.m_LineStyle, this.linePattern);
				this.m_lstDetailCurveId.Add(detailCurve.Id);
				this.isFirstPoint = true;
			}
			catch (Exception ex)
			{
				ex.ToString();
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private Result DeleteOutLine()
		{
			try
			{
				List<Element> list = new List<Element>();
				while (this.PickOutLine(ref list))
				{
					Transaction transaction = new Transaction(this.m_Doc);
					transaction.Start("delete outLine");
					foreach (Element element in list)
					{
						try
						{
							this.m_lstDetailCurveId.Remove(element.Id);
							this.m_Doc.Delete(element.Id);
						}
						catch (Exception)
						{
						}
					}
					transaction.Commit();
				}
			}
			catch (Exception ex)
			{
				ex.ToString();
				return Autodesk.Revit.UI.Result.Failed;
			}
			return Autodesk.Revit.UI.Result.Cancelled;
		}

		public static LinePatternElement CreateLinePatternElement(Autodesk.Revit.DB.Document doc, string patternName)
		{
			foreach (Element element in new FilteredElementCollector(doc).OfClass(typeof(LinePatternElement)).ToElements())
			{
				LinePatternElement linePatternElement = element as LinePatternElement;
				if (linePatternElement.Name == patternName)
				{
					return linePatternElement;
				}
			}
			List<LinePatternSegment> list = new List<LinePatternSegment>();
			list.Add(new LinePatternSegment((LinePatternSegmentType)0, 0.02));
			list.Add(new LinePatternSegment((LinePatternSegmentType)1, 0.03));
			list.Add(new LinePatternSegment((LinePatternSegmentType)0, 0.02));
			list.Add(new LinePatternSegment((LinePatternSegmentType)1, 0.03));
			LinePattern linePattern = new LinePattern(patternName);
			linePattern.SetSegments(list);
			Transaction transaction = new Transaction(doc, "Create a linepattern element");
			transaction.Start();
			LinePatternElement result = LinePatternElement.Create(doc, linePattern);
			transaction.Commit();
			return result;
		}

		private DetailCurve CreateDetailCurve(Autodesk.Revit.DB.Document doc, Curve curve, GraphicsStyle lineStyle, LinePatternElement linePattern)
		{
			Transaction transaction = new Transaction(doc, "DrawCurve");
			transaction.Start();
			DetailCurve detailCurve = doc.Create.NewDetailCurve(doc.ActiveView, curve);
			detailCurve.LineStyle = lineStyle;
			OverrideGraphicSettings overrideGraphicSettings = new OverrideGraphicSettings();
			overrideGraphicSettings.SetProjectionLinePatternId(linePattern.Id);
			doc.ActiveView.SetElementOverrides(detailCurve.Id, overrideGraphicSettings);
			transaction.Commit();
			return detailCurve;
		}

		public static List<Line> CreateRect(XYZ pt1, XYZ pt2)
		{
			XYZ xyz = new XYZ(pt1.X, pt2.Y, pt1.Z);
			XYZ xyz2 = new XYZ(pt2.X, pt1.Y, pt1.Z);
			return new List<Line>
			{
				Line.CreateBound(pt1, xyz),
				Line.CreateBound(xyz, pt2),
				Line.CreateBound(pt2, xyz2),
				Line.CreateBound(xyz2, pt1)
			};
		}

		public static Arc CreateArc(XYZ ptCenter, XYZ ptArcStart, XYZ ptArcEnd)
		{
			double length = (ptArcStart - ptCenter).GetLength();
			XYZ xyz = ptArcStart - ptCenter;
			XYZ xyz2 = ptArcEnd - ptCenter;
			xyz.AngleOnPlaneTo(xyz2, XYZ.BasisZ);
			double num;
			double num2;
			if (xyz.AngleOnPlaneTo(xyz2, XYZ.BasisZ) <= Math.PI)
			{
				num = XYZ.BasisX.AngleOnPlaneTo(xyz, XYZ.BasisZ);
				num2 = XYZ.BasisX.AngleOnPlaneTo(xyz2, XYZ.BasisZ);
				if (num > num2)
				{
					num2 += Math.PI*2;
				}
				return Arc.Create(ptCenter, length, num, num2, XYZ.BasisX, XYZ.BasisY);
			}
			num = XYZ.BasisX.Negate().AngleOnPlaneTo(xyz, XYZ.BasisZ.Negate());
			num2 = XYZ.BasisX.Negate().AngleOnPlaneTo(xyz2, XYZ.BasisZ.Negate());
			if (num > num2)
			{
				num2 += Math.PI*2;
			}
			return Arc.Create(ptCenter, length, num, num2, XYZ.BasisX.Negate(), XYZ.BasisY);
		}

		private bool PickEdge(ref Curve refCurve)
		{
			Reference reference = null;
			Selection selection = this.m_useApplication.ActiveUIDocument.Selection;
			try
			{
				EdgeFilter edgeFilter = new EdgeFilter(this.m_Doc);
				reference = selection.PickObject((Autodesk.Revit.UI.Selection.ObjectType)4, edgeFilter, "选择墙边界生成轮廓线");
			}
			catch (Exception)
			{
				return false;
			}
			if (reference == null)
			{
				return false;
			}
			Face face = this.m_Doc.GetElement(reference).GetGeometryObjectFromReference(reference) as Face;
			if (null == face)
			{
				return false;
			}
			XYZ globalPoint = reference.GlobalPoint;
			double val = double.MaxValue;
			Curve curve = null;
			foreach (object obj in face.EdgeLoops)
			{
				foreach (object obj2 in ((EdgeArray)obj))
				{
					Curve curve2 = ((Edge)obj2).AsCurve();
					XYZ endPoint = curve2.GetEndPoint(0);
					XYZ endPoint2 = curve2.GetEndPoint(1);
					if (Geometry.IsEqual(endPoint.Z, endPoint2.Z))
					{
						double num = curve2.Distance(new XYZ(globalPoint.X, globalPoint.Y, endPoint.Z));
						if (Geometry.LessThan(num, val))
						{
							val = num;
							curve = curve2;
						}
					}
				}
			}
			if (curve == null)
			{
				return false;
			}
			refCurve = curve;
			return true;
		}

		private void DrawLines(List<Curve> lines, bool bAdd2Array = false)
		{
			if (lines.Count == 0)
			{
				return;
			}
			Transaction transaction = null;
			try
			{
				transaction = new Transaction(this.m_Doc);
				transaction.Start("draw building outline");
				UIApplication useApplication = this.m_useApplication;
				CurveArray curveArray = new CurveArray();
				foreach (Curve curve in lines)
				{
					curveArray.Append(curve);
				}
				DetailCurveArray detailCurveArray = this.m_Doc.Create.NewDetailCurveArray(this.m_Doc.ActiveView, curveArray);
				if (this.GetLineStyle())
				{
					List<ElementId> list = new List<ElementId>();
					foreach (object obj in detailCurveArray)
					{
						DetailCurve detailCurve = (DetailCurve)obj;
						detailCurve.LineStyle = SelectAreaManager.m_LineStyle;
						list.Add(detailCurve.Id);
					}
					LinePatternElement linePatternElementByName = LinePatternElement.GetLinePatternElementByName(this.m_Doc, SelectAreaManager.m_strLinePatternName);
					if (linePatternElementByName != null)
					{
						this.m_Doc.ActiveView.SetYJKProjLinePatternOverrideByElement(list, linePatternElementByName);
					}
					if (bAdd2Array)
					{
						this.m_lstDetailCurveId.AddRange(list);
					}
				}
				transaction.Commit();
			}
			catch (Exception)
			{
				if (transaction != null)
				{
					transaction.RollBack();
				}
			}
		}

		private bool PickOutLine(ref List<Element> outLineList)
		{
			Selection selection = this.m_useApplication.ActiveUIDocument.Selection;
			try
			{
				OutLineFilter outLineFilter = new OutLineFilter(false);
				foreach (Element element in selection.PickElementsByRectangle(outLineFilter, "选择轮廓线"))
				{
					DetailCurve item = element as DetailCurve;
					outLineList.Add(item);
				}
			}
			catch (Exception ex)
			{
				ex.ToString();
				return false;
			}
			return true;
		}

		private bool GetLineStyle()
		{
			Category category = this.m_Doc.Settings.Categories.get_Item(BuiltInCategory.OST_Lines);
			if (category == null)
			{
				return false;
			}
			int nLineWidth = SelectAreaManager.m_nLineWidth;
			string text = SelectAreaManager.m_StrLineNamePrefix + nLineWidth.ToString();
            Autodesk.Revit.DB.Color lineColor = new Autodesk.Revit.DB.Color(byte.MaxValue, 0, byte.MaxValue);
			if (!category.SubCategories.Contains(text))
			{
				if (!this.CreateLineStyle(nLineWidth, text, lineColor, ref category))
				{
					return false;
				}
			}
			else
			{
				Category category2 = category.SubCategories.get_Item(text);
				category2.LineColor = lineColor;
				category2.SetLineWeight(nLineWidth, (Autodesk.Revit.DB.GraphicsStyleType)1);
			}
			foreach (Element element in new FilteredElementCollector(this.m_Doc).OfClass(typeof(GraphicsStyle)))
			{
				GraphicsStyle graphicsStyle = element as GraphicsStyle;
				if (graphicsStyle != null && graphicsStyle.Name.CompareTo(text) == 0)
				{
					SelectAreaManager.m_LineStyle = graphicsStyle;
				}
			}
			return SelectAreaManager.m_LineStyle != null;
		}

        private bool CreateLineStyle(int lineWidth, string typeName, Autodesk.Revit.DB.Color lineColor, ref Category lineCategory)
		{
			bool result;
			try
			{
				Category category = this.m_Doc.Settings.Categories.NewSubcategory(lineCategory, typeName);
				category.LineColor = lineColor;
				category.SetLineWeight(lineWidth, (Autodesk.Revit.DB.GraphicsStyleType)1);
				result = true;
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		private ExternalCommandData m_Revit;

		private UIApplication m_useApplication;

		private Document m_Doc;

		private bool m_bIsExistClose = true;

		private bool m_bIfOk;

		private bool m_bIfClose;

		private bool m_bIfWinFormClose;

		private static GraphicsStyle m_LineStyle = null;

		public static string m_StrLineNamePrefix = "HYProfileLine";

		public List<ElementId> m_lstDetailCurveId = new List<ElementId>();

		public List<Element> m_lstSelectRooms = new List<Element>();

		public bool m_bIsSave;

        public static WindowHandle _hWndRevit = null;

		private RoomFilter filter = new RoomFilter();

		private List<ElementId> m_TagCurves = new List<ElementId>();

		private static int m_nLineWidth = 3;

		private Selection m_sel;

		private static string m_strLinePatternName = "实线";

		private XYZ m_PickLastPoint;

		private XYZ pt1 = XYZ.Zero;

		private bool isFirstPoint = true;

		private LinePatternElement linePattern;
	}
}
